#include <iostream>
#include "zookeeperutil.h"
#include "mprpcapplication.h"
#include "logger.h"

// 全局的watcher观察器  zkserver给zkclient的通知
void global_watcher(zhandle_t *zh, int type, int state, const char* path, void* watcherCtx)
{
    if (type == ZOO_SESSION_EVENT) {
        // 回调的消息类型是和 会话相关的消息类型
        if (state == ZOO_CONNECTED_STATE) {
            // zkclient和zkserver连接成功
            sem_t* sem = (sem_t*)zoo_get_context(zh);
            sem_post(sem);
        }
    }
}

ZkClient::ZkClient() :m_zhandle(nullptr)
{}

ZkClient::~ZkClient()
{
    // 关闭zookeeper连接
    if (m_zhandle != nullptr) {
        zookeeper_close(m_zhandle);
    }
}

// 连接zkserver
void ZkClient::Start()
{
    std::string host = MprpcApplication::GetInstance().GetConfig().Load("zookeeperip");
    std::string port = MprpcApplication::GetInstance().GetConfig().Load("zookeeperport");
    std::string conn_str = host + ":" + port;

    // 初始化zookeeper  
    m_zhandle = zookeeper_init(conn_str.c_str(), global_watcher, 30000, nullptr, nullptr, 0);
    if (m_zhandle == nullptr) {
        // std::cout << "zookeeper_init error!" << std::endl;
        LOG_ERR("zookeeper_init error!");
        exit(EXIT_FAILURE);
    }

    sem_t sem;
    sem_init(&sem, 0, 0);
    zoo_set_context(m_zhandle, &sem);

    sem_wait(&sem);
    // std::cout << "zookeeper_init success!" << std::endl;
    LOG_INFO("zookeeper_init success!");
}

void ZkClient::Create(const char* path, const char* data, int datalen, int state)
{
    char path_buffer[128];
    int bufferlen = sizeof(path_buffer);
    int flag = zoo_exists(m_zhandle, path, 0, nullptr);
    if (ZNONODE == flag) {
        // 表示path的znode节点不存在
        // 创建指定path的znode节点
        flag = zoo_create(m_zhandle, path, data, datalen, &ZOO_OPEN_ACL_UNSAFE, state, path_buffer, bufferlen);
        if (flag == ZOK) {
            // std::cout << "znode create success, path: " << path << std::endl;
            LOG_INFO("znode create success, path: %s", path);
        }
        else {
            // std::cout << "flag: " << flag << std::endl;
            // std::cout << "znode create error, path: " <<  path << std::endl;
            LOG_ERR("znode create error, path: %s", path);
            exit(EXIT_FAILURE);
        }
    }
}

// 根据指定的path获取znode节点的值
std::string ZkClient::GetData(const char* path) 
{
    char buffer[64];
    int bufferlen = sizeof(buffer);
    int flag = zoo_get(m_zhandle, path, 0, buffer, &bufferlen, nullptr);
    if (flag != ZOK) {
        // 获取失败
        // std::cout << "get znode error, path: " << path << std::endl;
        LOG_ERR("get znode error, path: %s", path);
        return "";
    }
    else {
        return buffer;
    }
}